package Serveur;

import java.util.ArrayList;
import java.util.GregorianCalendar;
import java.util.Iterator;

import Both.Passager;
import Both.Trajet;
import Both.Transport;
import Both.TypeTransport;
import Both.Ville;
import Client.DemandeRechercheClient;
import ClientAdmin.DemandeModificationTrajet;
import ClientAdmin.DemandeModificationTransport;

/**
 * Classe Serveur
 * 
 * Cette classe possèdent toutes les fonctions nécessaires au fonctionnement de
 * l'application.
 * 
 * @author Jeremie Blond, Joris Harnetiaux, Mourade Assou, Nolan Potier
 * 
 */
public class Serveur {

    private static boolean singleton = false;
    private static Serveur instance;

    private ArrayList<Transport> listeTransport;
    private ArrayList<Trajet> listeTrajet;
    private ArrayList<Reservation> listeReservations;
    // Liste des utilisateurs inscrits
    private ArrayList<Passager> listePassager;

    private Serialization Files;

    public static String adminLogin = "admin";
    public static String adminPwd = "azerty";

    /**
     * Construteur normal
     */
    public Serveur() {
        // if (!singleton) {
        singleton = true;
        Files = new Serialization();

        listeTransport = Files.fillOutListeTransport();
        listeTrajet = Files.fillOutListeTrajet();
        listeReservations = Files.fillOutListeReservation();
        listePassager = Files.fillOutListePassager();

        instance = this;
        // } else {
        // System.out.println("Un serveur existe d�j�");
        // }
    }

    public static Serveur getInstance() {
        if (singleton)
            return instance;
        else
            return new Serveur();
    }

    /**
     * Accesseur de consultation de la liste des transports
     * 
     * @return
     */
    public ArrayList<Transport> getListeTransport() {
        return listeTransport;
    }

    /**
     * Accesseur de consultation de la liste des Reservations
     * 
     * @return
     */
    public ArrayList<Reservation> getListeReservations() {
        return listeReservations;
    }

    /**
     * Accesseur de consultation de la liste des Trajet
     * 
     * @return
     */
    public ArrayList<Trajet> getListeTrajet() {
        return listeTrajet;
    }

    /**
     * Afficher tous les transport
     */
    public void displayAllTransport() {
        Iterator<Transport> it = listeTransport.iterator();

        while (it.hasNext()) {
            Transport t = (Transport) it.next();
            t.print();
        }
    }

    /**
     * Afficher la liste des trajets
     */
    public void displayAllTrajet() {
        Iterator<Trajet> it = listeTrajet.iterator();

        while (it.hasNext()) {
            Trajet t = (Trajet) it.next();
            t.print();
        }
    }

    /**
     * Afficher toutes les reservations
     */
    public void displayAllReservations() {
        Iterator<Reservation> it = listeReservations.iterator();

        while (it.hasNext()) {
            Reservation res = (Reservation) it.next();
            res.print();
        }
    }

    /**
     * Fermer le serveur en serialisant les listes
     */
    public void closeServeur() {
        singleton = false;
        Files.close(listeTransport, listeTrajet, listeReservations,
                listePassager);
    }

    public ArrayList<Transport> searchTransport(TypeTransport type) {
        return Transport.searchTransport(listeTransport, type);
    }

    public void addReservation(Reservation R) {
        listeReservations.add(R);
    }

    public boolean addPassager(Passager P) {
        // Verifier si le trajet est present dans la liste
        if (getListePassager().contains(P)) {
            System.out.println("L'objet existe deja dans la liste");
            return false;
        }

        // Verifier que le login n'est pas deja utiliser
        for (Passager pa : getListePassager()) {
            if (pa.getLogin().equals(P.getLogin())) {
                System.out.println("Le login est deja utilise !");
                return false;
            }
        }

        // Ajouter le trajet a la liste
        if (!getListePassager().add(P)) {
            System.out.println("Impossible d'ajouter l'objet");
            return true;
        }

        return false;
    }

    public boolean analyserDemandeReservation(Reservation R) {
        return R.Reserver(this);
    }

    /**
     * Methode permettant d'analyser une commande pass�e par un client grace �
     * l'objet Reservation
     * 
     * @param rech
     * @return
     */
    public ArrayList<Trajet> analyserDemandeRecherche(
            DemandeRechercheClient rech) {
        return Trajet.searchTrajet(listeTrajet, rech.getVilledep(), rech
                .getVilleArr(), rech.getDateDep(), rech.getDateArr(), rech
                .getTrans(), rech.getNbPlace());
    }

    /**
     * Methode permettant de vider les listes du serveur
     */
    public void viderListes() {
        listeReservations.clear();
        listeTrajet.clear();
        listeTransport.clear();
        listePassager.clear();
    }

    /**
     * Modifier un transport
     * 
     * @param t
     * @param i
     */
    public boolean setTransport(Transport t, TypeTransport type, int numTrans,
            int capacite) {
        ArrayList<Transport> ListeTransport = getListeTransport();
        int indexMod = ListeTransport.indexOf(t);

        // Verifier que le transport existe dans le serveur
        if (indexMod == -1) {
            return false;
        }

        // Verifier tous les champs
        TypeTransport type2 = type;
        int numTrans2 = numTrans;
        int capacite2 = capacite;

        if (type == null) {
            type2 = t.getType();
        }
        if (numTrans == 0) {
            numTrans2 = t.getNumTrans();
        }
        if (capacite == 0) {
            capacite2 = t.getCapacite();
        }

        // verifier si les champs contiennent un /
        type2.toString().replace(Serialization.CAR_SPACE,
                Serialization.CAR_REPLACE);

        // Creer le nouvelle objet transport
        Transport tNew = new Transport(type2, numTrans2, capacite2);

        // Modifier l'objet dans la liste
        ListeTransport.set(indexMod, tNew);

        return true;
    }

    /**
     * Modifier un transport
     * 
     * @param t
     * @param i
     */
    public boolean setTransport(Transport old, Transport newTrans) {
        // Recuperer l'emplacement du transport dans la liste
        int index = getIndexOfTransport(old);

        try {
            getListeTransport().set(index, newTrans);
        } catch (Exception e) {
            return false;
        }

        return true;
    }

    /**
     * Modifier un transport
     * 
     * @param t
     * @param i
     */
    public boolean setTrajet(Trajet oldtraj, GregorianCalendar dateDep,
            GregorianCalendar dateArr, Ville villeDep, Ville villeArr,
            int placeOcc, Transport trans, double distance) {
        ArrayList<Trajet> listeTrajets = getListeTrajet();
        int indexMod = listeTrajets.indexOf(oldtraj);

        // Verifier que le transport existe dans le serveur
        if (indexMod == -1) {
            return false;
        }

        // Verifier tous les champs
        GregorianCalendar dateDep2 = dateDep;
        GregorianCalendar dateArr2 = dateArr;
        Ville villeDep2 = villeDep;
        Ville villeArr2 = villeArr;
        int placeOcc2 = placeOcc;
        Transport trans2 = trans;
        double distance2 = distance;

        if (dateDep == null) {
            dateDep2 = oldtraj.getDateDepart();
        }

        if (dateArr == null) {
            dateArr2 = oldtraj.getDateArrive();
        }

        if (villeDep == null) {
            villeDep2 = oldtraj.getVilleDepart();
        }

        if (villeArr == null) {
            villeArr2 = oldtraj.getVilleArrive();
        }

        if (trans == null) {
            trans2 = oldtraj.getTransport();
        }

        if (placeOcc == 0) {
            placeOcc2 = oldtraj.getPlaceOccuper();
        }

        if (distance == 0.0) {
            distance2 = oldtraj.getDistance();
        }

        // Creer le nouvelle objet transport
        Trajet newTraj = new Trajet(villeDep2, villeArr2, dateDep2, dateArr2,
                trans2, distance2);

        // Modifier l'objet dans la liste
        listeTrajets.set(indexMod, newTraj);

        return true;
    }

    /**
     * Modifier un transport
     * 
     * @param t
     * @param i
     */
    public boolean setTrajet(Trajet old, Trajet newTrans) {
        // Recuperer l'emplacement du transport dans la liste
        int index = getIndexOfTrajet(old);

        try {
            getListeTrajet().set(index, newTrans);
        } catch (Exception e) {
            return false;
        }

        return true;
    }

    /**
     * Recuperer l'index d'un transport
     */
    public int getIndexOfTransport(Transport t) {
        return getListeTransport().indexOf(t);
    }

    /**
     * Recuperer l'index d'un trajet
     */
    public int getIndexOfTrajet(Trajet t) {
        return getListeTrajet().indexOf(t);
    }

    /**
     * Ajouter un transport dans la liste
     * 
     * @param m
     */
    public void addTransport(Transport m) {
        // Verifier que le transport n'est pas deja present
        if (getListeTransport().contains(m)) {
            System.out.println("L'objet existe deja dans la liste");
            return;
        }
        // ajouter le tansport
        if (!getListeTransport().add(m)) {
            System.out.println("Impossible d'ajouter l'objet");
            return;
        }
    }

    /**
     * Modifier un transport avec les parametres donnees
     * 
     * @param dem
     * @return
     */
    public boolean analyserDemandeModificationTransportAdmin(
            DemandeModificationTransport dem) {
        if (dem.getCapacite() == 0 && dem.getType() == null
                && dem.getNum() == 0 && dem.getOldTrans() == null
                && dem.getNewTrans() != null) {
            addTransport(dem.getNewTrans());
            return true;
        }

        // Modification d'un transport avec les parametres
        if (dem.getNewTrans() != null && dem.getOldTrans() == null) {
            return setTransport(dem.getNewTrans(), dem.getType(), dem.getNum(),
                    dem.getCapacite());
        }

        // remplacement d'un transport par un autre
        if (dem.getCapacite() == 0 && dem.getType() == null
                && dem.getNum() == 0 && dem.getNewTrans() != null
                && dem.getOldTrans() != null) {
            return setTransport(dem.getOldTrans(), dem.getNewTrans());
        }

        return false;
    }

    /**
     * Modifier un transport avec les parametres donn�es
     * 
     * @param dem
     * @return
     */
    public boolean analyserDemandeModificationTrajetAdmin(
            DemandeModificationTrajet dem) {
        if (dem.getVilleDepart() == null && dem.getVilleArrive() == null
                && dem.getTrans() == null && dem.getPlaceOccuper() == 0
                && dem.getOld() == null && dem.getDateDepart() == null
                && dem.getDateArrive() == null && dem.getNewtraj() != null) {
            return addTrajet(dem.getNewtraj());
        }

        // Modification d'un transport avec les parametres
        if (dem.getNewtraj() != null && dem.getOld() != null) {
            return setTrajet(dem.getOld(), dem.getNewtraj());
        }

        // remplacement d'un transport par un autre
        if (dem.getNewtraj() == null) {
            return setTrajet(dem.getOld(), dem.getDateDepart(), dem
                    .getDateArrive(), dem.getVilleDepart(), dem
                    .getVilleArrive(), dem.getPlaceOccuper(), dem.getTrans(),
                    dem.getDistance());
        }

        return false;
    }

    /**
     * Ajouter un trajet dans la liste
     * 
     * @param m
     */
    public boolean addTrajet(Trajet m) {
        // Verifier si le trajet est present dans la liste
        if (getListeTrajet().contains(m)) {
            System.out.println("L'objet existe deja dans la liste");
            return true;
        }

        // Ajouter le trajet � la liste
        if (!getListeTrajet().add(m)) {
            System.out.println("Impossible d'ajouter l'objet");
            return true;
        }

        return false;
    }

    /**
     * Supprimer un transport
     * 
     * @param m
     */
    public boolean removeTransport(Transport m) {
        if (!getListeTransport().remove(m)) {
            return false;
        }
        return true;
    }

    /**
     * Supprimer un transport
     * 
     * @param m
     */
    public void removeTrajet(Trajet t) {
        if (!getListeTrajet().remove(t)) {
            System.out.println("Impossible d'enlever l'objet");
        }
    }

    /**
     * @return the listePassager
     */
    public ArrayList<Passager> getListePassager() {
        return listePassager;
    }

    /**
     * @param listePassager
     *            the listePassager to set
     */
    public void setListePassager(ArrayList<Passager> listePassager) {
        this.listePassager = listePassager;
    }

    /**
     * Otenir le passager correspondant au couple login - mot de passe
     */
    public Passager getPassager(String login, String mdp) {

        for (Passager p : getListePassager()) {
            if (p.getLogin().equals(login) && p.getMdp().equals(mdp)) {
                return p;
            }
        }
        return null;
    }
}
